<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="laravel-cashier-paddle" tabindex="-1"><a class="header-anchor" href="#laravel-cashier-paddle"><span>Laravel Cashier（Paddle）</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#upgrading-cashier">升级 Cashier</a></li>
<li><a href="#installation">安装</a>
<ul>
<li><a href="#paddle-sandbox">Paddle 沙盒</a></li>
</ul>
</li>
<li><a href="#configuration">配置</a>
<ul>
<li><a href="#billable-model">可账单模型</a></li>
<li><a href="#api-keys">API 密钥</a></li>
<li><a href="#paddle-js">Paddle JS</a></li>
<li><a href="#currency-configuration">货币配置</a></li>
<li><a href="#overriding-default-models">覆盖默认模型</a></li>
</ul>
</li>
<li><a href="#quickstart">快速入门</a>
<ul>
<li><a href="#quickstart-selling-products">销售产品</a></li>
<li><a href="#quickstart-selling-subscriptions">销售订阅</a></li>
</ul>
</li>
<li><a href="#checkout-sessions">结账会话</a>
<ul>
<li><a href="#overlay-checkout">覆盖式结账</a></li>
<li><a href="#inline-checkout">内联结账</a></li>
<li><a href="#guest-checkouts">访客结账</a></li>
</ul>
</li>
<li><a href="#price-previews">价格预览</a>
<ul>
<li><a href="#customer-price-previews">客户价格预览</a></li>
<li><a href="#price-discounts">折扣</a></li>
</ul>
</li>
<li><a href="#customers">客户</a>
<ul>
<li><a href="#customer-defaults">客户默认设置</a></li>
<li><a href="#retrieving-customers">检索客户</a></li>
<li><a href="#creating-customers">创建客户</a></li>
</ul>
</li>
<li><a href="#subscriptions">订阅</a>
<ul>
<li><a href="#creating-subscriptions">创建订阅</a></li>
<li><a href="#checking-subscription-status">检查订阅状态</a></li>
<li><a href="#subscription-single-charges">订阅单次收费</a></li>
<li><a href="#updating-payment-information">更新付款信息</a></li>
<li><a href="#changing-plans">更改计划</a></li>
<li><a href="#subscription-quantity">订阅数量</a></li>
<li><a href="#subscriptions-with-multiple-products">具有多个产品的订阅</a></li>
<li><a href="#multiple-subscriptions">多个订阅</a></li>
<li><a href="#pausing-subscriptions">暂停订阅</a></li>
<li><a href="#canceling-subscriptions">取消订阅</a></li>
</ul>
</li>
<li><a href="#subscription-trials">订阅试用</a>
<ul>
<li><a href="#with-payment-method-up-front">有付款方式的试用</a></li>
<li><a href="#without-payment-method-up-front">无付款方式的试用</a></li>
<li><a href="#extend-or-activate-a-trial">延长或激活试用</a></li>
</ul>
</li>
<li><a href="#handling-paddle-webhooks">处理 Paddle Webhooks</a>
<ul>
<li><a href="#defining-webhook-event-handlers">定义 Webhook 事件处理程序</a></li>
<li><a href="#verifying-webhook-signatures">验证 Webhook 签名</a></li>
</ul>
</li>
<li><a href="#single-charges">单次收费</a>
<ul>
<li><a href="#charging-for-products">为产品收费</a></li>
<li><a href="#refunding-transactions">退款交易</a></li>
<li><a href="#crediting-transactions">信用交易</a></li>
</ul>
</li>
<li><a href="#transactions">交易</a>
<ul>
<li><a href="#past-and-upcoming-payments">过去和即将到来的付款</a></li>
</ul>
</li>
<li><a href="#testing">测试</a></li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<blockquote>
<p><strong>警告</strong><br>
本文档适用于 Cashier Paddle 2.x 与 Paddle 计费集成。如果你仍在使用 Paddle Classic，请使用 <a href="https://github.com/laravel/cashier-paddle/tree/1.x" target="_blank" rel="noopener noreferrer">Cashier Paddle 1.x</a>。</p>
</blockquote>
<p><a href="https://github.com/laravel/cashier-paddle" target="_blank" rel="noopener noreferrer">Laravel Cashier Paddle</a> 提供了一个富有表现力、流畅的界面，用于<a href="https://paddle.com/" target="_blank" rel="noopener noreferrer">Paddle</a>的订阅计费服务。它处理几乎所有你所担心的样板式订阅计费代码。除了基本的订阅管理外，Cashier 还可以处理：订阅切换、订阅“数量”、订阅暂停、取消期限宽限等。</p>
<p>在深入了解 Cashier Paddle 之前，我们建议你也查看 Paddle 的 <a href="https://developer.paddle.com/concepts/overview" target="_blank" rel="noopener noreferrer">概念指南</a> 和 <a href="https://developer.paddle.com/api-reference/overview" target="_blank" rel="noopener noreferrer">API 文档</a>。</p>
<h2 id="升级-cashier" tabindex="-1"><a class="header-anchor" href="#升级-cashier"><span>升级 Cashier</span></a></h2>
<p>在升级到 Cashier 的新版本时，重要的是仔细阅读 <a href="https://github.com/laravel/cashier-paddle/blob/master/UPGRADE.md" target="_blank" rel="noopener noreferrer">升级指南</a>。</p>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<p>首先，使用 Composer 包管理器安装 Paddle 的 Cashier 包：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require laravel/cashier-paddle</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，你应该使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Cashier 迁移文件：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--tag</span><span class="token operator">=</span><span class="token string">"cashier-migrations"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>然后，你应该运行应用程序的数据库迁移。Cashier 迁移将创建一个新的 <code v-pre>customers</code> 表。此外，将创建新的 <code v-pre>subscriptions</code> 和 <code v-pre>subscription_items</code> 表来存储所有客户的订阅。最后，将创建一个新的 <code v-pre>transactions</code> 表来存储与你的客户关联的所有 Paddle 交易：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>[!WARNING]<br>
为确保 Cashier 正确处理所有 Paddle 事件，请记得 <a href="#handling-paddle-webhooks">设置 Cashier 的 Webhook 处理</a>。</p>
</blockquote>
<h3 id="paddle-沙盒" tabindex="-1"><a class="header-anchor" href="#paddle-沙盒"><span>Paddle 沙盒</span></a></h3>
<p>在本地开发和测试阶段，你应该 <a href="https://sandbox-login.paddle.com/signup" target="_blank" rel="noopener noreferrer">注册一个 Paddle 沙盒账户</a>。这个账户将为你提供一个沙盒环境，用于测试和开发你的应用程序，而不进行实际支付。你可以使用 Paddle 的 <a href="https://developer.paddle.com/concepts/payment-methods/credit-debit-card" target="_blank" rel="noopener noreferrer">测试卡号</a> 来模拟各种支付情景。</p>
<p>当使用 Paddle 沙盒环境时，你应该在应用程序的 <code v-pre>.env</code> 文件中将 <code v-pre>PADDLE_SANDBOX</code> 环境变量设置为 <code v-pre>true</code>：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">PADDLE_SANDBOX</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>开发完成后，你可以<a href="https://paddle.com/" target="_blank" rel="noopener noreferrer">申请 Paddle 商家账户</a>。在将你的应用程序投入生产之前，Paddle 需要批准你的应用程序域名。</p>
<h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<h3 id="可账单模型" tabindex="-1"><a class="header-anchor" href="#可账单模型"><span>可账单模型</span></a></h3>
<p>在使用 Cashier 之前，你必须将 <code v-pre>Billable</code> 特性添加到用户模型定义中。该特性提供了各种方法，允许你执行常见的计费任务，如创建订阅和更新付款方式信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Billable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Billable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果有不是用户的可账单实体，你也可以将该特性添加到这些类中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Billable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Team</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Billable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="api-密钥" tabindex="-1"><a class="header-anchor" href="#api-密钥"><span>API 密钥</span></a></h3>
<p>接下来，你应该在应用程序的 <code v-pre>.env</code> 文件中配置你的 Paddle 密钥。你可以从 Paddle 控制面板中检索到你的 Paddle API 密钥：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">PADDLE_CLIENT_SIDE_TOKEN</span><span class="token punctuation">=</span><span class="token value attr-value">your-paddle-client-side-token</span></span>
<span class="line"><span class="token key attr-name">PADDLE_API_KEY</span><span class="token punctuation">=</span><span class="token value attr-value">your-paddle-api-key</span></span>
<span class="line"><span class="token key attr-name">PADDLE_RETAIN_KEY</span><span class="token punctuation">=</span><span class="token value attr-value">your-paddle-retain-key</span></span>
<span class="line"><span class="token key attr-name">PADDLE_WEBHOOK_SECRET</span><span class="token punctuation">=</span><span class="token value attr-value">"<span class="token inner-value">your-paddle-webhook-secret</span>"</span></span>
<span class="line"><span class="token key attr-name">PADDLE_SANDBOX</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当你使用<a href="#paddle-sandbox">Paddle 的沙盒环境</a>时，<code v-pre>PADDLE_SANDBOX</code> 环境变量应设置为 <code v-pre>true</code>。如果你将应用程序部署到生产环境并使用 Paddle 的实际商家环境，则应将 <code v-pre>PADDLE_SANDBOX</code> 变量设置为 <code v-pre>false</code>。</p>
<p><code v-pre>PADDLE_RETAIN_KEY</code> 是可选的，只有在你使用 Paddle 与 <a href="https://developer.paddle.com/paddlejs/retain" target="_blank" rel="noopener noreferrer">Retain</a> 时才需要设置。</p>
<h3 id="paddle-js" tabindex="-1"><a class="header-anchor" href="#paddle-js"><span>Paddle JS</span></a></h3>
<p>Paddle 依赖于自己的 JavaScript 库来启动 Paddle 结账小部件。你可以通过在应用程序布局的闭合 <code v-pre>&lt;/head&gt;</code> 标签之前放置 <code v-pre>@paddleJS</code> Blade 指令来加载 JavaScript 库：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;head&gt;</span>
<span class="line">    ...</span>
<span class="line"></span>
<span class="line">    @paddleJS</span>
<span class="line">&lt;/head&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="货币配置" tabindex="-1"><a class="header-anchor" href="#货币配置"><span>货币配置</span></a></h3>
<p>你可以指定一个区域设置，用于在发票上显示货币值时进行格式化。在内部，Cashier 利用 <a href="https://www.php.net/manual/en/class.numberformatter.php" target="_blank" rel="noopener noreferrer">PHP 的 <code v-pre>NumberFormatter</code> 类</a> 来设置货币区域设置：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_CURRENCY_LOCALE</span><span class="token punctuation">=</span><span class="token value attr-value">nl_BE</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
若要使用除 <code v-pre>en</code> 外的区域设置，请确保在服务器上安装并配置了 <code v-pre>ext-intl</code> PHP 扩展。</p>
</blockquote>
<h3 id="覆盖默认模型" tabindex="-1"><a class="header-anchor" href="#覆盖默认模型"><span>覆盖默认模型</span></a></h3>
<p>你可以通过定义自己的模型并扩展相应的 Cashier 模型来自由扩展 Cashier 内部使用的模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Subscription</span> <span class="token keyword">as</span> CashierSubscription<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Subscription</span> <span class="token keyword">extends</span> <span class="token class-name">CashierSubscription</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>定义完你的模型后，你可以通过 <code v-pre>Laravel\Paddle\Cashier</code> 类指示 Cashier 使用你的自定义模型。通常，在应用程序的 <code v-pre>App\Providers\AppServiceProvider</code> 类的 <code v-pre>boot</code> 方法中，你应该通知 Cashier 关于你的自定义模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Subscription</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Transaction</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 引导任何应用服务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">useSubscriptionModel</span><span class="token punctuation">(</span><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">useTransactionModel</span><span class="token punctuation">(</span><span class="token class-name static-context">Transaction</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="快速入门" tabindex="-1"><a class="header-anchor" href="#快速入门"><span>快速入门</span></a></h2>
<h3 id="销售产品" tabindex="-1"><a class="header-anchor" href="#销售产品"><span>销售产品</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
在使用 Paddle 结账之前，你应该在 Paddle 仪表板中定义具有固定价格的产品。此外，你应该<a href="#handling-paddle-webhooks">配置 Paddle 的 Webhook 处理</a>。</p>
</blockquote>
<p>通过你的应用程序提供产品和订阅计费可能会让人望而生畏。然而，借助 Cashier 和 <a href="https://www.paddle.com/billing/checkout" target="_blank" rel="noopener noreferrer">Paddle 的结账覆盖层</a>，你可以轻松构建现代、强大的支付集成。</p>
<p>为了向客户收取非重复性、单次收费产品的费用，我们将利用 Cashier 通过 Paddle 的结账覆盖层向客户收费，在那里他们将提供他们的付款详细信息并确认购买。一旦通过结账覆盖层进行了支付，客户将被重定向到你在应用程序中选择的成功 URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_deluxe_album'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'buy'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如上面的示例所示，我们将利用 Cashier 提供的 <code v-pre>checkout</code> 方法来创建一个结账对象，向客户展示 Paddle 结账覆盖层，针对给定的「价格标识符」。在使用 Paddle 时，「价格」指的是<a href="https://developer.paddle.com/build/products/create-products-prices" target="_blank" rel="noopener noreferrer">针对特定产品定义的价格</a>。</p>
<p>如果有必要，<code v-pre>checkout</code> 方法将自动在 Paddle 中创建一个客户，并将该 Paddle 客户记录连接到你的应用程序数据库中相应的用户。完成结账会话后，客户将被重定向到一个专门的成功页面，在那里你可以向客户显示信息性消息。</p>
<p>在 <code v-pre>buy</code> 视图中，我们将包含一个按钮来显示结账覆盖层。<code v-pre>paddle-button</code> Blade 组件与 Cashier Paddle 一起提供；但是，你也可以<a href="#manually-rendering-an-overlay-checkout">手动呈现覆盖层结账</a>：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>x-paddle-button</span> <span class="token attr-name">:checkout</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$checkout<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-8 py-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    购买产品</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>x-paddle-button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="向-paddle-结账提供元数据" tabindex="-1"><a class="header-anchor" href="#向-paddle-结账提供元数据"><span>向 Paddle 结账提供元数据</span></a></h4>
<p>在销售产品时，通过你自己应用程序定义的 <code v-pre>Cart</code> 和 <code v-pre>Order</code> 模型，跟踪已完成的订单和购买的产品是很常见的。当将客户重定向到 Paddle 的结账覆盖层以完成购买时，你可能需要提供一个现有的订单标识符，以便在客户重定向回你的应用程序时将已完成的购买与相应的订单关联起来。</p>
<p>为了实现这一点，你可以向 <code v-pre>checkout</code> 方法提供一个自定义数据数组。让我们假设在我们的应用程序中，当用户开始结账过程时，会创建一个待处理的 <code v-pre>Order</code>。请记住，此示例中的 <code v-pre>Cart</code> 和 <code v-pre>Order</code> 模型仅用于说明，Cashier 不提供这些模型。你可以根据你的应用程序需求自由实现这些概念：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cart</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/cart/{cart}/checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Cart</span> <span class="token variable">$cart</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$order</span> <span class="token operator">=</span> <span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'cart_id'</span> <span class="token operator">=></span> <span class="token variable">$cart</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_ids'</span> <span class="token operator">=></span> <span class="token variable">$cart</span><span class="token operator">-></span><span class="token property">price_ids</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'status'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'incomplete'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token variable">$order</span><span class="token operator">-></span><span class="token property">price_ids</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">customData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'order_id'</span> <span class="token operator">=></span> <span class="token variable">$order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如上面的示例所示，当用户开始结账过程时，我们将向 <code v-pre>checkout</code> 方法提供所有购物车/订单关联的 Paddle 价格标识符。当客户将这些项目添加到购物车或订单时，你的应用程序负责将它们与之关联。我们还通过 <code v-pre>customData</code> 方法向 Paddle 结账覆盖层提供订单的 ID。</p>
<p>当客户完成结账过程后，你可能希望将订单标记为“完成”。为了实现这一点，你可以监听 Paddle 发送的 Webhook，并通过 Cashier 触发的事件来将订单信息存储在你的数据库中。</p>
<p>要开始，请监听 Cashier 发送的 <code v-pre>TransactionCompleted</code> 事件。通常情况下，你应该在应用程序的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中注册事件监听器：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Listeners<span class="token punctuation">\</span>CompleteOrder</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Event</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>TransactionCompleted</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 引导任何应用服务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Event</span><span class="token operator">::</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token class-name static-context">TransactionCompleted</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name static-context">CompleteOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个示例中，<code v-pre>CompleteOrder</code> 监听器可能如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>TransactionCompleted</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">CompleteOrder</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理传入的 Cashier Webhook 事件。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">TransactionCompleted</span> <span class="token variable">$event</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$orderId</span> <span class="token operator">=</span> <span class="token variable">$event</span><span class="token operator">-></span><span class="token property">payload</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'custom_data'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'order_id'</span><span class="token punctuation">]</span> <span class="token operator">??</span> <span class="token constant">null</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$order</span> <span class="token operator">=</span> <span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token function">findOrFail</span><span class="token punctuation">(</span><span class="token variable">$orderId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$order</span><span class="token operator">-></span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'status'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'completed'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>请参考 Paddle 的文档，了解有关 <a href="https://developer.paddle.com/webhooks/transactions/transaction-completed" target="_blank" rel="noopener noreferrer"><code v-pre>transaction.completed</code> 事件包含的数据</a>的更多信息。</p>
<h3 id="销售订阅" tabindex="-1"><a class="header-anchor" href="#销售订阅"><span>销售订阅</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
在使用 Paddle 结账之前，你应该在 Paddle 仪表板中定义具有固定价格的产品。此外，你应该<a href="#handling-paddle-webhooks">配置 Paddle 的 Webhook 处理</a>。</p>
</blockquote>
<p>通过你的应用程序提供产品和订阅计费可能会让人感到畏惧。然而，借助 Cashier 和 <a href="https://www.paddle.com/billing/checkout" target="_blank" rel="noopener noreferrer">Paddle 的结账覆盖层</a>，你可以轻松构建现代、强大的支付集成。</p>
<p>要了解如何使用 Cashier 和 Paddle 的结账覆盖层销售订阅，让我们考虑一个简单的场景，即一个具有基本月度（<code v-pre>price_basic_monthly</code>）和年度（<code v-pre>price_basic_yearly</code>）计划的订阅服务。这两个价格可以在我们的 Paddle 仪表板下的“基本”产品（<code v-pre>pro_basic</code>）下进行分组。此外，我们的订阅服务可能还提供一个专家计划作为 <code v-pre>pro_expert</code>。</p>
<p>首先，让我们了解客户如何订阅我们的服务。当然，你可以想象客户可能会在我们应用程序的定价页面上点击“订阅”按钮以选择基本计划。此按钮将为他们选择的计划调用 Paddle 结账覆盖层。要开始，请通过 <code v-pre>checkout</code> 方法启动结账会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_basic_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'subscribe'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'subscribe'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在 <code v-pre>subscribe</code> 视图中，我们将包含一个按钮来显示结账覆盖层。<code v-pre>paddle-button</code> Blade 组件与 Cashier Paddle 一起提供；但是，你也可以<a href="#manually-rendering-an-overlay-checkout">手动呈现覆盖层结账</a>：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>x-paddle-button</span> <span class="token attr-name">:checkout</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$checkout<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-8 py-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    订阅</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>x-paddle-button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当客户点击订阅按钮时，他们将能够输入付款详细信息并启动他们的订阅。为了知道他们的订阅实际上何时开始（因为一些支付方式需要几秒钟来处理），你还应该<a href="#handling-paddle-webhooks">配置 Cashier 的 Webhook 处理</a>。</p>
<p>现在客户可以开始订阅了，我们需要限制应用程序的某些部分，以便只有订阅用户才能访问它们。当然，我们始终可以通过 Cashier 的 <code v-pre>Billable</code> 特性提供的 <code v-pre>subscribed</code> 方法来确定用户当前的订阅状态：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if ($user-&gt;subscribed())</span>
<span class="line">    &lt;p&gt;你已订阅。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>我们甚至可以轻松确定用户是否订阅了特定产品或价格：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if ($user-&gt;subscribedToProduct('pro_basic'))</span>
<span class="line">    &lt;p&gt;你已订阅我们的基本产品。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span>
<span class="line">@if ($user-&gt;subscribedToPrice('price_basic_monthly'))</span>
<span class="line">    &lt;p&gt;你已订阅我们的月度基本计划。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="构建一个订阅中间件" tabindex="-1"><a class="header-anchor" href="#构建一个订阅中间件"><span>构建一个订阅中间件</span></a></h4>
<p>为了方便起见，你可能希望创建一个<a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">中间件</a>，用于确定传入请求是否来自订阅用户。一旦定义了这个中间件，你可以轻松地将其分配给一个路由，以防止未订阅的用户访问该路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Symfony<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>HttpFoundation<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Subscribed</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理传入请求。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 将用户重定向到付款页面并要求他们订阅...</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscribe'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦定义了中间件，你可以将其分配给一个路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>Subscribed</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/dashboard'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name static-context">Subscribed</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="允许客户管理他们的计费计划" tabindex="-1"><a class="header-anchor" href="#允许客户管理他们的计费计划"><span>允许客户管理他们的计费计划</span></a></h4>
<p>当然，客户可能希望将他们的订阅计划更改为另一个产品或“层级”。在上面的示例中，我们希望允许客户将他们的计划从月度订阅更改为年度订阅。为此，你需要实现类似以下路由的按钮：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription/{price}/swap'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$price</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token variable">$price</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 在这个示例中，"$price" 为 "price_basic_yearly"。</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'subscription.swap'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>除了更改计划，你还需要允许客户取消他们的订阅。类似更改计划，提供一个按钮，指向以下路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription/cancel'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$price</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'subscription.cancel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在，你的订阅将在其计费周期结束时被取消。</p>
<blockquote>
<p><strong>注意</strong><br>
只要你已经配置了 Cashier 的 Webhook 处理，Cashier 将通过检查来自 Paddle 的传入 Webhook 自动保持你的应用程序的与 Cashier 相关的数据库表同步。因此，例如，当你通过 Paddle 的仪表板取消客户的订阅时，Cashier 将接收相应的 Webhook 并在你的应用程序数据库中将订阅标记为“已取消”。</p>
</blockquote>
<h2 id="结账会话" tabindex="-1"><a class="header-anchor" href="#结账会话"><span>结账会话</span></a></h2>
<p>大多数向客户收费的操作都是通过 Paddle 的<a href="https://developer.paddle.com/build/checkout/build-overlay-checkout" target="_blank" rel="noopener noreferrer">结账覆盖窗口小部件</a>或利用<a href="https://developer.paddle.com/build/checkout/build-branded-inline-checkout" target="_blank" rel="noopener noreferrer">内联结账</a>来执行的。</p>
<p>在使用 Paddle 处理结账付款之前，你应该在 Paddle 结账设置仪表板中定义你的应用程序的<a href="https://developer.paddle.com/build/transactions/default-payment-link#set-default-link" target="_blank" rel="noopener noreferrer">默认付款链接</a>。</p>
<h3 id="覆盖窗口结账" tabindex="-1"><a class="header-anchor" href="#覆盖窗口结账"><span>覆盖窗口结账</span></a></h3>
<p>在显示结账覆盖窗口小部件之前，你必须使用 Cashier 生成一个结账会话。结账会话将通知结账小部件应执行的计费操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_34567'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Cashier 包含一个 <code v-pre>paddle-button</code> <a href="https://learnku.com/docs/laravel/11.x/blade#components" target="_blank" rel="noopener noreferrer">Blade 组件</a>。你可以将结账会话作为 &quot;prop&quot; 传递给这个组件。然后，当点击此按钮时，Paddle 的结账小部件将显示：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>x-paddle-button</span> <span class="token attr-name">:checkout</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$checkout<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-8 py-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    Subscribe</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>x-paddle-button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，这将使用 Paddle 的默认样式显示小部件。你可以通过向组件添加<a href="https://developer.paddle.com/paddlejs/html-data-attributes" target="_blank" rel="noopener noreferrer">Paddle 支持的属性</a>，如 <code v-pre>data-theme='light'</code> 属性来自定义小部件：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>x-paddle-button</span> <span class="token attr-name">:url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$payLink<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-8 py-4<span class="token punctuation">"</span></span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>light<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    Subscribe</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>x-paddle-button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Paddle 结账小部件是异步的。一旦用户在小部件内创建了一个订阅，Paddle 将向你的应用程序发送一个 Webhook，以便你可以正确更新应用程序数据库中的订阅状态。因此，重要的是你正确地<a href="#handling-paddle-webhooks">设置 Webhooks</a>以适应来自 Paddle 的状态更改。</p>
<blockquote>
<p><strong>警告</strong><br>
在订阅状态更改后，接收相应 Webhook 的延迟通常很小，但你应该在你的应用程序中考虑到这一点，考虑到用户的订阅可能在完成结账后不会立即可用。</p>
</blockquote>
<h4 id="手动渲染覆盖窗口结账" tabindex="-1"><a class="header-anchor" href="#手动渲染覆盖窗口结账"><span>手动渲染覆盖窗口结账</span></a></h4>
<p>你也可以在不使用 Laravel 内置 Blade 组件的情况下手动渲染覆盖窗口结账。首先，生成结账会话<a href="#overlay-checkout">如前面示例所示</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_34567'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，你可以使用 Paddle.js 来初始化结账。在这个示例中，我们将创建一个链接，分配 <code v-pre>paddle_button</code> 类。Paddle.js 将检测到这个类，并在点击链接时显示覆盖窗口结账：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token variable">$items</span> <span class="token operator">=</span> <span class="token variable">$checkout</span><span class="token operator">-></span><span class="token function">getItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token variable">$checkout</span><span class="token operator">-></span><span class="token function">getCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$custom</span> <span class="token operator">=</span> <span class="token variable">$checkout</span><span class="token operator">-></span><span class="token function">getCustomData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token delimiter important">?></span></span></span>
<span class="line"></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span></span>
<span class="line"><span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>#!<span class="token punctuation">'</span></span></span>
<span class="line"><span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>paddle_button<span class="token punctuation">'</span></span></span>
<span class="line"><span class="token attr-name">data-items</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>{!! json_encode($items) !!}<span class="token punctuation">'</span></span></span>
<span class="line"><span class="token attr-name">@if</span> <span class="token attr-name">($customer)</span> <span class="token attr-name">data-customer-id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>{{ $customer->paddle_id }}<span class="token punctuation">'</span></span> <span class="token attr-name">@endif</span></span>
<span class="line"><span class="token attr-name">@if</span> <span class="token attr-name">($custom)</span> <span class="token attr-name">data-custom-data</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>{{ json_encode($custom) }}<span class="token punctuation">'</span></span> <span class="token attr-name">@endif</span></span>
<span class="line"><span class="token attr-name">@if</span> <span class="token attr-name">($returnUrl</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> $checkout-</span><span class="token punctuation">></span></span>getReturnUrl()) data-success-url='{{ $returnUrl }}' @endif</span>
<span class="line">></span>
<span class="line">购买产品</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="内联结账" tabindex="-1"><a class="header-anchor" href="#内联结账"><span>内联结账</span></a></h3>
<p>如果你不想使用 Paddle 的“覆盖”样式结账小部件，Paddle 还提供了在页面内显示小部件的选项。虽然这种方法不允许你调整任何结账的 HTML 字段，但它允许你将小部件嵌入到你的应用程序中。</p>
<p>为了让你更容易开始使用内联结账，Cashier 包含了一个 <code v-pre>paddle-checkout</code> Blade 组件。要开始，你应该<a href="#overlay-checkout">生成一个结账会话</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_34567'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，你可以将结账会话传递给组件的 <code v-pre>checkout</code> 属性：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;x-paddle-checkout :checkout=&quot;$checkout&quot; class=&quot;w-full&quot; /&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要调整内联结账组件的高度，你可以将 <code v-pre>height</code> 属性传递给 Blade 组件：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;x-paddle-checkout :checkout=&quot;$checkout&quot; class=&quot;w-full&quot; height=&quot;500&quot; /&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>请参考 Paddle 的<a href="https://developer.paddle.com/build/checkout/build-branded-inline-checkout" target="_blank" rel="noopener noreferrer">内联结账指南</a>和<a href="https://developer.paddle.com/build/checkout/set-up-checkout-default-settings" target="_blank" rel="noopener noreferrer">可用结账设置</a>以获取有关内联结账自定义选项的更多详细信息。</p>
<h4 id="手动渲染内联结账" tabindex="-1"><a class="header-anchor" href="#手动渲染内联结账"><span>手动渲染内联结账</span></a></h4>
<p>你也可以在不使用 Laravel 内置 Blade 组件的情况下手动渲染内联结账。首先，生成结账会话<a href="#inline-checkout">如前面示例所示</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_34567'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，你可以使用 Paddle.js 来初始化结账。在这个示例中，我们将使用<a href="https://github.com/alpinejs/alpine" target="_blank" rel="noopener noreferrer">Alpine.js</a>来演示；然而，你可以自由修改此示例以适应你自己的前端堆栈：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;?php</span>
<span class="line">$options = $checkout-&gt;options();</span>
<span class="line"></span>
<span class="line">$options['settings']['frameTarget'] = 'paddle-checkout';</span>
<span class="line">$options['settings']['frameInitialHeight'] = 366;</span>
<span class="line">?&gt;</span>
<span class="line"></span>
<span class="line">&lt;div class=&quot;paddle-checkout&quot; x-data=&quot;{}&quot; x-init=&quot;</span>
<span class="line">    Paddle.Checkout.open(@json($options));</span>
<span class="line">&quot;&gt;</span>
<span class="line">&lt;/div&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="访客结账" tabindex="-1"><a class="header-anchor" href="#访客结账"><span>访客结账</span></a></h3>
<p>有时，你可能需要为不需要在你的应用程序中拥有帐户的用户创建一个结账会话。为此，你可以使用 <code v-pre>guest</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Checkout</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token class-name static-context">Checkout</span><span class="token operator">::</span><span class="token function">guest</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_34567'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，你可以将结账会话提供给 <a href="#overlay-checkout">Paddle 按钮</a> 或 <a href="#inline-checkout">内联结账</a> Blade 组件。</p>
<h2 id="价格预览" tabindex="-1"><a class="header-anchor" href="#价格预览"><span>价格预览</span></a></h2>
<p>Paddle 允许你根据货币自定义价格，基本上允许你为不同国家配置不同的价格。Cashier Paddle 允许你使用 <code v-pre>previewPrices</code> 方法检索所有这些价格。该方法接受你希望检索价格的价格 ID：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$prices</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">previewPrices</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>货币将根据请求的 IP 地址确定；但是，你可以选择性地提供一个特定的国家代码来检索价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$prices</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">previewPrices</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'address'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'country_code'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'BE'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'postal_code'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'1234'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在检索价格后，你可以按照你希望的方式显示它们：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>ul<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$prices</span> <span class="token keyword">as</span> <span class="token variable">$price</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">&lt;</span>li<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$price</span><span class="token operator">-></span><span class="token property">product</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$price</span><span class="token operator">-></span><span class="token function">total</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">endforeach</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以单独显示小计价格和税额：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>ul<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$prices</span> <span class="token keyword">as</span> <span class="token variable">$price</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">&lt;</span>li<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$price</span><span class="token operator">-></span><span class="token property">product</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$price</span><span class="token operator">-></span><span class="token function">subtotal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">(</span><span class="token operator">+</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$price</span><span class="token operator">-></span><span class="token function">tax</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> 税<span class="token punctuation">)</span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">endforeach</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有关更多信息，请参阅<a href="https://developer.paddle.com/api-reference/pricing-preview/preview-prices" target="_blank" rel="noopener noreferrer">Paddle 的关于价格预览的 API 文档</a>。</p>
<h3 id="用户价格预览" tabindex="-1"><a class="header-anchor" href="#用户价格预览"><span>用户价格预览</span></a></h3>
<p>如果用户已经是客户，并且你想显示适用于该客户的价格，你可以通过直接从客户实例检索价格来实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$prices</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">previewPrices</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在内部，Cashier 将使用用户的客户 ID 来检索他们货币的价格。例如，居住在美国的用户将看到美元价格，而居住在比利时的用户将看到欧元价格。如果找不到匹配的货币，将使用产品的默认货币。你可以在 Paddle 控制面板中自定义产品或订阅计划的所有价格。</p>
<h3 id="折扣" tabindex="-1"><a class="header-anchor" href="#折扣"><span>折扣</span></a></h3>
<p>你也可以选择显示折扣后的价格。在调用 <code v-pre>previewPrices</code> 方法时，通过 <code v-pre>discount_id</code> 选项提供折扣 ID：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$prices</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">previewPrices</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'discount_id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'dsc_123'</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，显示计算后的价格：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;ul&gt;</span>
<span class="line">    @foreach ($prices as $price)</span>
<span class="line">        &lt;li&gt;{{ $price-&gt;product['name'] }} - {{ $price-&gt;total() }}&lt;/li&gt;</span>
<span class="line">    @endforeach</span>
<span class="line">&lt;/ul&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="客户" tabindex="-1"><a class="header-anchor" href="#客户"><span>客户</span></a></h2>
<h3 id="客户默认值" tabindex="-1"><a class="header-anchor" href="#客户默认值"><span>客户默认值</span></a></h3>
<p>Cashier 允许你为创建结账会话时的客户定义一些有用的默认值。设置这些默认值可以预先填充客户的电子邮件地址和姓名，以便他们可以立即转向结账小部件的付款部分。你可以通过覆盖你的可账单模型上的以下方法来设置这些默认值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取与 Paddle 关联的客户姓名。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">paddleName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取与 Paddle 关联的客户电子邮件地址。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">paddleEmail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">email</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这些默认值将用于 Cashier 中生成<a href="#checkout-sessions">结账会话</a>的每个操作。</p>
<h3 id="检索客户" tabindex="-1"><a class="header-anchor" href="#检索客户"><span>检索客户</span></a></h3>
<p>你可以使用 <code v-pre>Cashier::findBillable</code> 方法根据他们的 Paddle 客户 ID 检索客户。该方法将返回可账单模型的实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">findBillable</span><span class="token punctuation">(</span><span class="token variable">$customerId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="创建客户" tabindex="-1"><a class="header-anchor" href="#创建客户"><span>创建客户</span></a></h3>
<p>偶尔，你可能希望创建一个 Paddle 客户而不开始订阅。你可以使用 <code v-pre>createAsCustomer</code> 方法来实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>返回一个 <code v-pre>Laravel\Paddle\Customer</code> 的实例。一旦客户在 Paddle 中创建成功，你可以在以后的某个日期开始订阅。你可以提供一个可选的 <code v-pre>$options</code> 数组，以传递任何额外的<a href="https://developer.paddle.com/api-reference/customers/create-customer" target="_blank" rel="noopener noreferrer">由 Paddle API 支持的客户创建参数</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsCustomer</span><span class="token punctuation">(</span><span class="token variable">$options</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="订阅" tabindex="-1"><a class="header-anchor" href="#订阅"><span>订阅</span></a></h2>
<h3 id="创建订阅" tabindex="-1"><a class="header-anchor" href="#创建订阅"><span>创建订阅</span></a></h3>
<p>要创建一个订阅，首先从数据库中检索你的可账单模型的实例，通常这将是 <code v-pre>App\Models\User</code> 的实例。一旦你检索到模型实例，你可以使用 <code v-pre>subscribe</code> 方法来创建模型的结账会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token number">12345</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>传递给 <code v-pre>subscribe</code> 方法的第一个参数是用户要订阅的特定价格。这个值应该对应于 Paddle 中价格的标识符。<code v-pre>returnTo</code> 方法接受一个 URL，在用户成功完成结账后将重定向到该 URL。传递给 <code v-pre>subscribe</code> 方法的第二个参数应该是订阅的内部“类型”。如果你的应用程序只提供单个订阅，你可以将其称为 <code v-pre>default</code> 或 <code v-pre>primary</code>。这个订阅类型仅用于内部应用程序使用，不应显示给用户。此外，它不应包含空格，并且在创建订阅后不应更改。</p>
<p>你还可以使用 <code v-pre>customData</code> 方法提供有关订阅的自定义元数据数组：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token number">12345</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">customData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'key'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'value'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦创建了订阅结账会话，可以将该结账会话提供给 Cashier Paddle 提供的 <code v-pre>paddle-button</code> <a href="#overlay-checkout">Blade 组件</a>：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;x-paddle-button :checkout=&quot;$checkout&quot; class=&quot;px-8 py-4&quot;&gt;</span>
<span class="line">    Subscribe</span>
<span class="line">&lt;/x-paddle-button&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>用户完成结账后，Paddle 将发送一个 <code v-pre>subscription_created</code> webhook。Cashier 将接收此 webhook 并为你的客户设置订阅。为确保所有 webhook 得到正确接收和处理，请确保你已经正确<a href="#handling-paddle-webhooks">设置了 webhook 处理</a>。</p>
<h3 id="检查订阅状态" tabindex="-1"><a class="header-anchor" href="#检查订阅状态"><span>检查订阅状态</span></a></h3>
<p>一旦用户订阅了你的应用程序，你可以使用各种便捷的方法来检查他们的订阅状态。首先，<code v-pre>subscribed</code> 方法在用户拥有有效订阅时返回 <code v-pre>true</code>，即使订阅目前处于试用期内：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你的应用程序提供多个订阅，你可以在调用 <code v-pre>subscribed</code> 方法时指定订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>subscribed</code> 方法也非常适合用作<a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">路由中间件</a>的候选，允许你根据用户的订阅状态过滤对路由和控制器的访问：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Symfony<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>HttpFoundation<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">EnsureUserIsSubscribed</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理传入请求。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>Closure</span>(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 这个用户不是付费客户...</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想确定用户是否仍处于试用期内，可以使用 <code v-pre>onTrial</code> 方法。这个方法可用于确定是否应向用户显示警告，告诉他们他们仍处于试用期内：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>subscribedToPrice</code> 方法可用于确定用户是否根据给定的 Paddle 价格 ID 订阅了特定计划。在这个例子中，我们将确定用户的 <code v-pre>default</code> 订阅是否已经订阅了月度价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribedToPrice</span><span class="token punctuation">(</span><span class="token variable">$monthly</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>recurring</code> 方法可用于确定用户当前是否处于活跃订阅状态，不再处于试用期或宽限期内：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">recurring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="已取消订阅状态" tabindex="-1"><a class="header-anchor" href="#已取消订阅状态"><span>已取消订阅状态</span></a></h4>
<p>要确定用户曾经是活跃订阅者但已取消订阅，可以使用 <code v-pre>canceled</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以确定用户是否已取消订阅，但仍处于“宽限期”直到订阅完全到期。例如，如果用户在3月5日取消了原定于3月10日到期的订阅，用户将在3月10日之前处于“宽限期”。此外，在此期间，<code v-pre>subscribed</code> 方法仍将返回 <code v-pre>true</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="拖欠状态" tabindex="-1"><a class="header-anchor" href="#拖欠状态"><span>拖欠状态</span></a></h4>
<p>如果订阅付款失败，它将被标记为 <code v-pre>past_due</code>。在订阅处于这种状态时，直到客户更新他们的付款信息，它将不会处于活跃状态。你可以使用订阅实例上的 <code v-pre>pastDue</code> 方法来确定订阅是否拖欠：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pastDue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当订阅拖欠时，你应指导用户<a href="#updating-payment-information">更新他们的付款信息</a>。</p>
<p>如果你希望在订阅处于 <code v-pre>past_due</code> 状态时仍将其视为有效，可以使用 Cashier 提供的 <code v-pre>keepPastDueSubscriptionsActive</code> 方法。通常，这个方法应该在你的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>register</code> 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册任何应用程序服务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">keepPastDueSubscriptionsActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
当订阅处于 <code v-pre>past_due</code> 状态时，直到付款信息已更新，它不能被更改。因此，当订阅处于 <code v-pre>past_due</code> 状态时，<code v-pre>swap</code> 和 <code v-pre>updateQuantity</code> 方法将抛出异常。</p>
</blockquote>
<h4 id="订阅范围" tabindex="-1"><a class="header-anchor" href="#订阅范围"><span>订阅范围</span></a></h4>
<p>大多数订阅状态也可作为查询范围，以便你可以轻松地查询处于特定状态的订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 获取所有有效订阅...</span></span>
<span class="line"><span class="token variable">$subscriptions</span> <span class="token operator">=</span> <span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 获取用户的所有已取消订阅...</span></span>
<span class="line"><span class="token variable">$subscriptions</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscriptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>下面是可用范围的完整列表：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">expiredTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notOnTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">recurring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pastDue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">paused</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notPaused</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onPausedGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notOnPausedGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notCanceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notOnGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="订阅单次收费" tabindex="-1"><a class="header-anchor" href="#订阅单次收费"><span>订阅单次收费</span></a></h3>
<p>订阅单次收费允许你在订阅的基础上向订阅者收取一次性费用。在调用 <code v-pre>charge</code> 方法时，你必须提供一个或多个价格 ID：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 收取单个价格...</span></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 一次性收取多个价格...</span></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>charge</code> 方法实际上不会在用户的订阅的下一个计费周期之前向用户收费。如果你想立即向用户收费，可以改用 <code v-pre>chargeAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">chargeAndInvoice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="更新付款信息" tabindex="-1"><a class="header-anchor" href="#更新付款信息"><span>更新付款信息</span></a></h3>
<p>Paddle 总是为每个订阅保存一个付款方式。如果你想更新订阅的默认付款方式，应该使用订阅模型上的 <code v-pre>redirectToUpdatePaymentMethod</code> 方法，将客户重定向到 Paddle 的托管付款方式更新页面：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/update-payment-method'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectToUpdatePaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当用户完成信息更新后，Paddle 将会发送一个 <code v-pre>subscription_updated</code> webhook，并且订阅详情将会在你的应用程序数据库中更新。</p>
<h3 id="更改计划" tabindex="-1"><a class="header-anchor" href="#更改计划"><span>更改计划</span></a></h3>
<p>用户订阅你的应用程序后，他们可能偶尔想要切换到一个新的订阅计划。要为用户更新订阅计划，应该将 Paddle 价格标识符传递给订阅的 <code v-pre>swap</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要立即切换计划并向用户开具发票，而不必等待他们的下一个计费周期，可以使用 <code v-pre>swapAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swapAndInvoice</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="比例调整" tabindex="-1"><a class="header-anchor" href="#比例调整"><span>比例调整</span></a></h4>
<p>默认情况下，Paddle 在不同计划之间切换时会按比例计算费用。<code v-pre>noProrate</code> 方法可用于在不按比例计费的情况下更新订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想禁用比例调整并立即向客户开具发票，可以结合使用 <code v-pre>swapAndInvoice</code> 方法和 <code v-pre>noProrate</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swapAndInvoice</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>或者，如果你不想为订阅更改向客户开具账单，可以使用 <code v-pre>doNotBill</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">doNotBill</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token variable">$premium</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>欲了解更多关于 Paddle 的比例调整政策，请参阅 Paddle 的<a href="https://developer.paddle.com/concepts/subscriptions/proration" target="_blank" rel="noopener noreferrer">比例调整文档</a>。</p>
<h3 id="订阅数量" tabindex="-1"><a class="header-anchor" href="#订阅数量"><span>订阅数量</span></a></h3>
<p>有时订阅会受到“数量”的影响。例如，项目管理应用程序可能会按每个项目每月 $10 收费。要轻松增加或减少订阅的数量，请使用 <code v-pre>incrementQuantity</code> 和 <code v-pre>decrementQuantity</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 将五个添加到订阅的当前数量...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 从订阅的当前数量减去五个...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>updateQuantity</code> 方法设置特定的数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>使用 <code v-pre>noProrate</code> 方法可以在不按比例计费的情况下更新订阅的数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="带有多个产品的订阅数量" tabindex="-1"><a class="header-anchor" href="#带有多个产品的订阅数量"><span>带有多个产品的订阅数量</span></a></h4>
<p>如果你的订阅是<a href="#subscriptions-with-multiple-products">带有多个产品的订阅</a>，应将你希望增加或减少数量的价格 ID 作为第二个参数传递给增加/减少方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="带有多个产品的订阅" tabindex="-1"><a class="header-anchor" href="#带有多个产品的订阅"><span>带有多个产品的订阅</span></a></h3>
<p><a href="https://developer.paddle.com/build/subscriptions/add-remove-products-prices-addons" target="_blank" rel="noopener noreferrer">带有多个产品的订阅</a>允许你为单个订阅分配多个计费产品。例如，假设你正在构建一个客户服务“帮助台”应用程序，基本订阅价格为每月 $10，但提供额外的每月 $15 的实时聊天附加产品。</p>
<p>在创建订阅结账会话时，你可以通过将价格数组作为 <code v-pre>subscribe</code> 方法的第一个参数来为给定订阅指定多个产品：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上面的示例中，客户将有两个价格附加到他们的 <code v-pre>default</code> 订阅上。这两个价格将在各自的计费间隔上收费。如果需要，你可以传递一个键/值对的关联数组来指示每个价格的特定数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想向现有订阅添加另一个价格，必须使用订阅的 <code v-pre>swap</code> 方法。在调用 <code v-pre>swap</code> 方法时，你还应包括订阅的当前价格和数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_original'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的示例将添加新价格，但客户直到下一个计费周期才会被收费。如果你想立即向客户收费，可以使用 <code v-pre>swapAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swapAndInvoice</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_original'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>swap</code> 方法从订阅中移除价格，并省略你想要移除的价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_original'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
你不能移除订阅中的最后一个价格。相反，你应该简单地取消订阅。</p>
</blockquote>
<h3 id="多个订阅" tabindex="-1"><a class="header-anchor" href="#多个订阅"><span>多个订阅</span></a></h3>
<p>Paddle 允许你的客户同时拥有多个订阅。例如，你可能经营一个健身房，提供游泳订阅和举重订阅，每个订阅可能有不同的定价。当然，客户应该能够订阅其中一个或两个计划。</p>
<p>当你的应用程序创建订阅时，你可以将订阅类型作为第二个参数传递给 <code v-pre>subscribe</code> 方法。类型可以是任何表示用户发起的订阅类型的字符串：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/swimming/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token variable">$swimmingMonthly</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个示例中，我们为客户启动了一个每月的游泳订阅。然而，他们可能会在以后想要切换到年度订阅。当调整客户的订阅时，我们可以简单地在 <code v-pre>swimming</code> 订阅上交换价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token variable">$swimmingYearly</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'pri_456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当然，你也可以完全取消订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="暂停订阅" tabindex="-1"><a class="header-anchor" href="#暂停订阅"><span>暂停订阅</span></a></h3>
<p>要暂停订阅，请在用户的订阅上调用 <code v-pre>pause</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当订阅暂停时，Cashier 将自动在你的数据库中设置 <code v-pre>paused_at</code> 列。该列用于确定 <code v-pre>paused</code> 方法何时应开始返回 <code v-pre>true</code>。例如，如果客户在3月1日暂停了订阅，但订阅原定于3月5日才重新发生，<code v-pre>paused</code> 方法将继续返回 <code v-pre>false</code>，直到3月5日。这是因为通常允许用户在他们的计费周期结束之前继续使用应用程序。</p>
<p>默认情况下，暂停将在下一个计费间隔发生，以便客户可以使用他们支付的剩余时间。如果你想立即暂停订阅，可以使用 <code v-pre>pauseNow</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pauseNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>使用 <code v-pre>pauseUntil</code> 方法，你可以将订阅暂停直到特定时间：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pauseUntil</span><span class="token punctuation">(</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>pauseNowUntil</code> 方法立即暂停订阅直到给定时间点：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pauseNowUntil</span><span class="token punctuation">(</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>onPausedGracePeriod</code> 方法确定用户是否已暂停他们的订阅，但仍处于“宽限期”：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onPausedGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要恢复暂停的订阅，你可以在订阅上调用 <code v-pre>resume</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
订阅在暂停期间无法修改。如果你想切换到不同的计划或更新数量，你必须先恢复订阅。</p>
</blockquote>
<h3 id="取消订阅" tabindex="-1"><a class="header-anchor" href="#取消订阅"><span>取消订阅</span></a></h3>
<p>要取消订阅，请在用户的订阅上调用 <code v-pre>cancel</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当订阅被取消时，Cashier 将自动在你的数据库中设置 <code v-pre>ends_at</code> 列。该列用于确定 <code v-pre>subscribed</code> 方法何时应开始返回 <code v-pre>false</code>。例如，如果客户在3月1日取消了订阅，但订阅原定于3月5日才结束，<code v-pre>subscribed</code> 方法将继续返回 <code v-pre>true</code>，直到3月5日。这是因为通常允许用户在他们的计费周期结束之前继续使用应用程序。</p>
<p>你可以使用 <code v-pre>onGracePeriod</code> 方法确定用户是否已取消他们的订阅，但仍处于“宽限期”：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你希望立即取消订阅，你可以在订阅上调用 <code v-pre>cancelNow</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要阻止处于宽限期的订阅被取消，你可以调用 <code v-pre>stopCancelation</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">stopCancelation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>[!WARNING]<br>
Paddle 的订阅在取消后无法恢复。如果你的客户希望恢复他们的订阅，他们将不得不创建一个新的订阅。</p>
</blockquote>
<h2 id="订阅试用" tabindex="-1"><a class="header-anchor" href="#订阅试用"><span>订阅试用</span></a></h2>
<h3 id="预先设置付款方式" tabindex="-1"><a class="header-anchor" href="#预先设置付款方式"><span>预先设置付款方式</span></a></h3>
<p>如果你想为客户提供试用期，同时仍然在一开始收集付款方式信息，你应该在 Paddle 仪表板上为客户订阅的价格设置一个试用时间。然后，像平常一样启动结账会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当你的应用程序接收到 <code v-pre>subscription_created</code> 事件时，Cashier 将在应用程序数据库中的订阅记录上设置试用期结束日期，并指示 Paddle 在此日期之后开始向客户计费。</p>
<blockquote>
<p><strong>警告</strong><br>
如果客户的订阅在试用结束日期之前未取消，他们将在试用到期后立即收费，因此你应该确保通知用户他们的试用结束日期。</p>
</blockquote>
<p>你可以使用用户实例的 <code v-pre>onTrial</code> 方法或订阅实例的 <code v-pre>onTrial</code> 方法来确定用户是否在试用期内。以下两个示例是等效的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要确定现有试用是否已过期，你可以使用 <code v-pre>hasExpiredTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasExpiredTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasExpiredTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要确定用户是否针对特定订阅类型处于试用期，你可以向 <code v-pre>onTrial</code> 或 <code v-pre>hasExpiredTrial</code> 方法提供类型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasExpiredTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="不预先设置付款方式" tabindex="-1"><a class="header-anchor" href="#不预先设置付款方式"><span>不预先设置付款方式</span></a></h3>
<p>如果你想在不预先收集用户付款方式信息的情况下提供试用期，你可以在附加到用户的客户记录上设置 <code v-pre>trial_ends_at</code> 列为你期望的试用结束日期。这通常在用户注册期间完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsCustomer</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'trial_ends_at'</span> <span class="token operator">=></span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Cashier 将此类型的试用称为“通用试用”，因为它不附加到任何现有订阅。<code v-pre>User</code> 实例上的 <code v-pre>onTrial</code> 方法将在当前日期未超过 <code v-pre>trial_ends_at</code> 的值时返回 <code v-pre>true</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户处于试用期内...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦你准备为用户创建实际订阅，你可以像平常一样使用 <code v-pre>subscribe</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">returnTo</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要获取用户的试用结束日期，你可以使用 <code v-pre>trialEndsAt</code> 方法。如果用户在试用期内，该方法将返回一个 Carbon 日期实例，如果他们不在试用期内，则返回 <code v-pre>null</code>。如果你想获取除默认订阅以外的特定订阅的试用结束日期，你也可以传递一个可选的订阅类型参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$trialEndsAt</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">trialEndsAt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想具体知道用户是否在他们的“通用”试用期内并且尚未创建实际订阅，你可以使用 <code v-pre>onGenericTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onGenericTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户处于他们的「通用」试用期内...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="延长或激活试用期" tabindex="-1"><a class="header-anchor" href="#延长或激活试用期"><span>延长或激活试用期</span></a></h3>
<p>你可以通过调用 <code v-pre>extendTrial</code> 方法并指定试用结束的时间来延长订阅上的现有试用期：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">extendTrial</span><span class="token punctuation">(</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>或者，你可以通过在订阅上调用 <code v-pre>activate</code> 方法结束其试用期来立即激活订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">activate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="处理-paddle-webhooks" tabindex="-1"><a class="header-anchor" href="#处理-paddle-webhooks"><span>处理 Paddle Webhooks</span></a></h2>
<p>Paddle 可以通过 Webhooks 向你的应用程序通知各种事件。默认情况下，Cashier 服务提供程序注册了一个指向 Cashier Webhook 控制器的路由。该控制器将处理所有传入的 Webhook 请求。</p>
<p>默认情况下，此控制器将自动处理取消订阅、订阅更新和付款方式更改等事件；然而，正如我们将很快发现的那样，你可以扩展此控制器以处理任何你喜欢的 Paddle Webhook 事件。</p>
<p>为确保你的应用程序能够处理 Paddle Webhooks，请确保在 Paddle 控制面板中<a href="https://vendors.paddle.com/alerts-webhooks" target="_blank" rel="noopener noreferrer">配置 Webhook URL</a>。默认情况下，Cashier 的 Webhook 控制器响应 <code v-pre>/paddle/webhook</code> URL 路径。你应该在 Paddle 控制面板中启用的所有 Webhooks 的完整列表包括：</p>
<ul>
<li>Customer Updated</li>
<li>Transaction Completed</li>
<li>Transaction Updated</li>
<li>Subscription Created</li>
<li>Subscription Updated</li>
<li>Subscription Paused</li>
<li>Subscription Canceled</li>
</ul>
<blockquote>
<p><strong>警告</strong><br>
确保使用 Cashier 包含的<a href="https://learnku.com/docs/laravel/11.x/cashier-paddle#verifying-webhook-signatures" target="_blank" rel="noopener noreferrer">Webhook 签名验证</a>中间件保护传入请求。</p>
</blockquote>
<h4 id="webhooks-和-csrf-保护" tabindex="-1"><a class="header-anchor" href="#webhooks-和-csrf-保护"><span>Webhooks 和 CSRF 保护</span></a></h4>
<p>由于 Paddle Webhooks 需要绕过 Laravel 的 <a href="https://learnku.com/docs/laravel/11.x/csrf" target="_blank" rel="noopener noreferrer">CSRF 保护</a>，你应确保 Laravel 不会尝试验证传入的 Paddle Webhooks 的 CSRF 令牌。为实现此目的，你应在应用程序的 <code v-pre>bootstrap/app.php</code> 文件中将 <code v-pre>paddle/*</code> 排除在 CSRF 保护之外：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">-></span><span class="token function">withMiddleware</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Middleware</span> <span class="token variable">$middleware</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$middleware</span><span class="token operator">-></span><span class="token function">validateCsrfTokens</span><span class="token punctuation">(</span><span class="token argument-name">except</span><span class="token punctuation">:</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'paddle/*'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="webhooks-和本地开发" tabindex="-1"><a class="header-anchor" href="#webhooks-和本地开发"><span>Webhooks 和本地开发</span></a></h4>
<p>为了让 Paddle 能够在本地开发期间向你的应用程序发送 Webhooks，你需要通过站点共享服务（如<a href="https://ngrok.com/" target="_blank" rel="noopener noreferrer">Ngrok</a>或<a href="https://expose.dev/docs/introduction" target="_blank" rel="noopener noreferrer">Expose</a>）公开你的应用程序。如果你正在使用 <a href="https://learnku.com/docs/laravel/11.x/sail" target="_blank" rel="noopener noreferrer">Laravel Sail</a> 在本地开发你的应用程序，你可以使用 Sail 的 <a href="https://learnku.com/docs/laravel/11.x/sail#sharing-your-site" target="_blank" rel="noopener noreferrer">站点共享命令</a>。</p>
<h3 id="定义-webhook-事件处理程序" tabindex="-1"><a class="header-anchor" href="#定义-webhook-事件处理程序"><span>定义 Webhook 事件处理程序</span></a></h3>
<p>Cashier 自动处理订阅失败付款和其他常见的 Paddle Webhooks 上的取消操作。然而，如果你有其他 Webhook 事件需要处理，你可以通过监听 Cashier 发出的以下事件来实现：</p>
<ul>
<li><code v-pre>Laravel\Paddle\Events\WebhookReceived</code></li>
<li><code v-pre>Laravel\Paddle\Events\WebhookHandled</code></li>
</ul>
<p>这两个事件都包含 Paddle Webhook 的完整负载。例如，如果你希望处理 <code v-pre>transaction.billed</code> Webhook，你可以注册一个<a href="https://learnku.com/docs/laravel/11.x/events#defining-listeners" target="_blank" rel="noopener noreferrer">监听器</a>来处理该事件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Paddle<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>WebhookReceived</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PaddleEventListener</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理接收到的 Paddle Webhooks。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebhookReceived</span> <span class="token variable">$event</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-></span><span class="token property">payload</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'event_type'</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'transaction.billed'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 处理传入的事件...</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Cashier 还会针对接收到的 Webhook 类型发出专用事件。除了来自 Paddle 的完整负载外，它们还包含用于处理 Webhook 的相关模型，如可计费模型、订阅或收据：</p>
<ul>
<li><code v-pre>Laravel\Paddle\Events\CustomerUpdated</code></li>
<li><code v-pre>Laravel\Paddle\Events\TransactionCompleted</code></li>
<li><code v-pre>Laravel\Paddle\Events\TransactionUpdated</code></li>
<li><code v-pre>Laravel\Paddle\Events\SubscriptionCreated</code></li>
<li><code v-pre>Laravel\Paddle\Events\SubscriptionUpdated</code></li>
<li><code v-pre>Laravel\Paddle\Events\SubscriptionPaused</code></li>
<li><code v-pre>Laravel\Paddle\Events\SubscriptionCanceled</code></li>
</ul>
<p>你还可以通过在应用程序的 <code v-pre>.env</code> 文件中定义 <code v-pre>CASHIER_WEBHOOK</code> 环境变量来覆盖默认的内置 Webhook 路由。此值应为你的 Webhook 路由的完整 URL，并且需要与 Paddle 控制面板中设置的 URL 匹配：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_WEBHOOK</span><span class="token punctuation">=</span><span class="token value attr-value">https://example.com/my-paddle-webhook-url</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="验证-webhook-签名" tabindex="-1"><a class="header-anchor" href="#验证-webhook-签名"><span>验证 Webhook 签名</span></a></h3>
<p>为了保护你的 Webhooks，你可以使用<a href="https://developer.paddle.com/webhook-reference/verifying-webhooks" target="_blank" rel="noopener noreferrer">Paddle 的 Webhook 签名</a>。为了方便起见，Cashier 自动包含一个中间件，用于验证传入的 Paddle Webhook 请求是否有效。</p>
<p>要启用 Webhook 验证，请确保在应用程序的 <code v-pre>.env</code> 文件中定义了 <code v-pre>PADDLE_WEBHOOK_SECRET</code> 环境变量。Webhook 密钥可以从你的 Paddle 帐户仪表板中获取。</p>
<h2 id="单次收费" tabindex="-1"><a class="header-anchor" href="#单次收费"><span>单次收费</span></a></h2>
<h3 id="为产品收费" tabindex="-1"><a class="header-anchor" href="#为产品收费"><span>为产品收费</span></a></h3>
<p>如果你想为客户发起产品购买，你可以在可计费模型实例上使用 <code v-pre>checkout</code> 方法为购买生成结账会话。<code v-pre>checkout</code> 方法接受一个或多个价格 ID。如果需要，可以使用关联数组来提供正在购买的产品数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/buy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'pri_tshirt'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_socks'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'buy'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>生成结账会话后，你可以使用 Cashier 提供的 <code v-pre>paddle-button</code> <a href="#overlay-checkout">Blade 组件</a>来让用户查看 Paddle 结账小部件并完成购买：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;x-paddle-button :checkout=&quot;$checkout&quot; class=&quot;px-8 py-4&quot;&gt;</span>
<span class="line">    购买</span>
<span class="line">&lt;/x-paddle-button&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>结账会话具有 <code v-pre>customData</code> 方法，允许你向底层交易创建传递任何自定义数据。请参考<a href="https://developer.paddle.com/build/transactions/custom-data" target="_blank" rel="noopener noreferrer">Paddle 文档</a>以了解在传递自定义数据时可用的选项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pri_tshirt'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">customData</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'custom_option'</span> <span class="token operator">=></span> <span class="token variable">$value</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="退款交易" tabindex="-1"><a class="header-anchor" href="#退款交易"><span>退款交易</span></a></h3>
<p>退款交易将退还已退款金额至客户购买时使用的支付方式。如果你需要退款 Paddle 购买，你可以在 <code v-pre>Cashier\Paddle\Transaction</code> 模型上使用 <code v-pre>refund</code> 方法。该方法将接受一个原因作为第一个参数，一个或多个价格ID用于退款，可选金额作为关联数组。你可以使用 <code v-pre>transactions</code> 方法检索给定可计费模型的交易。</p>
<p>例如，假设我们想要为价格 <code v-pre>pri_123</code> 和 <code v-pre>pri_456</code> 退款特定交易。我们想要完全退款 <code v-pre>pri_123</code>，但只退还 <code v-pre>pri_456</code> 两美元：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$transaction</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">transactions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">refund</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'意外收费'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">,</span> <span class="token comment">// 完全退款此价格...</span></span>
<span class="line">    <span class="token string single-quoted-string">'pri_456'</span> <span class="token operator">=></span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token comment">// 仅部分退款此价格...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的示例退款交易中的特定行项目。如果要退还整个交易，请简单提供一个原因：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">refund</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'意外收费'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>有关退款的更多信息，请参考<a href="https://developer.paddle.com/build/transactions/create-transaction-adjustments" target="_blank" rel="noopener noreferrer">Paddle 的退款文档</a>。</p>
<blockquote>
<p><strong>警告</strong><br>
在完全处理之前，退款必须始终经过 Paddle 批准。</p>
</blockquote>
<h3 id="信用交易" tabindex="-1"><a class="header-anchor" href="#信用交易"><span>信用交易</span></a></h3>
<p>与退款类似，你也可以对交易进行信用处理。信用交易将向客户的余额中添加资金，以便将来可以用于购买。只能对手动收取的交易进行信用处理，不能对自动收取的交易（如订阅）进行信用处理，因为 Paddle 会自动处理订阅的信用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$transaction</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">transactions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 对特定行项目进行全额信用处理...</span></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">credit</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'补偿'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pri_123'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>欲了解更多信息，请参阅<a href="https://developer.paddle.com/build/transactions/create-transaction-adjustments" target="_blank" rel="noopener noreferrer">Paddle 关于信用处理的文档</a>。</p>
<blockquote>
<p><strong>警告</strong><br>
只能对手动收取的交易进行信用处理。自动收取的交易由 Paddle 自行处理。</p>
</blockquote>
<h2 id="交易" tabindex="-1"><a class="header-anchor" href="#交易"><span>交易</span></a></h2>
<p>你可以通过 <code v-pre>transactions</code> 属性轻松检索可计费模型的交易数组：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$transactions</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">transactions</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>交易代表你的产品和购买的付款，并附带发票。只有已完成的交易才会存储在应用程序的数据库中。</p>
<p>在列出客户的交易时，你可以使用交易实例的方法来显示相关的付款信息。例如，你可以希望在表格中列出每笔交易，让用户可以轻松下载任何发票：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">></span></span></span>
<span class="line">    @foreach ($transactions as $transaction)</span>
<span class="line">        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">></span></span></span>
<span class="line">            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>{{ $transaction->billed_at->toFormattedDateString() }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span></span>
<span class="line">            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>{{ $transaction->total() }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span></span>
<span class="line">            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span>{{ $transaction->tax() }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span></span>
<span class="line">            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ route('download-invoice', $transaction->id) }}<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>下载<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">></span></span></span>
<span class="line">        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">></span></span></span>
<span class="line">    @endforeach</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>download-invoice</code> 路由可能如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Transaction</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/download-invoice/{transaction}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Transaction</span> <span class="token variable">$transaction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">redirectToInvoicePdf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'download-invoice'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="过往和即将到期的付款" tabindex="-1"><a class="header-anchor" href="#过往和即将到期的付款"><span>过往和即将到期的付款</span></a></h3>
<p>你可以使用 <code v-pre>lastPayment</code> 和 <code v-pre>nextPayment</code> 方法来检索并显示客户循环订阅的过往或即将到期的付款：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$subscription</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$lastPayment</span> <span class="token operator">=</span> <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">lastPayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$nextPayment</span> <span class="token operator">=</span> <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">nextPayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这两个方法都将返回一个 <code v-pre>Laravel\Paddle\Payment</code> 实例；但是，当交易尚未通过 Webhooks 同步时，<code v-pre>lastPayment</code> 将返回 <code v-pre>null</code>，而当计费周期结束时（例如当订阅已取消时），<code v-pre>nextPayment</code> 将返回 <code v-pre>null</code>：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">下次付款：{{ $nextPayment-&gt;amount() }}，截止日期 {{ $nextPayment-&gt;date()-&gt;format('d/m/Y') }}</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>在测试过程中，你应该手动测试你的计费流程，以确保你的集成按预期工作。</p>
<p>对于自动化测试，包括在 CI 环境中执行的测试，你可以使用<a href="https://learnku.com/docs/laravel/11.x/http-client#testing" target="_blank" rel="noopener noreferrer">Laravel 的 HTTP 客户端</a>来模拟对 Paddle 发出的 HTTP 调用。虽然这不会测试来自 Paddle 的实际响应，但它提供了一种在不实际调用 Paddle API 的情况下测试你的应用程序的方法。</p>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/cashier-paddlemd/16716" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/ca...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/cashier-paddlemd/16716" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/ca...</a></p>
</blockquote>
</div></template>


